﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.Xml.Linq;

namespace QQSideShowCreator {
    public partial class MainForm : Form {
        public MainForm() {
            InitializeComponent();
            
			_profiles = new Hashtable();
			LoadProfiles();

            // Additional UI Initialization
            textOutputFolder.Text = Environment.GetFolderPath( Environment.SpecialFolder.MyDocuments );
            pictureBox1.Show();
            labelRectSize.Text = "{ " + pictureBox1.Width + " × " + pictureBox1.Height + " }";

			// Component that shall be re-initialized manually
			this.Text = FORM_TITLE_PREFIX + " V" +
				System.Reflection.Assembly.GetExecutingAssembly().GetName().Version.ToString();
			;
			IEnumerator keyEnumerator = _profiles.Keys.GetEnumerator();
			while ( keyEnumerator.MoveNext() )
				listBoxProfilesAvailable.Items.Add(keyEnumerator.Current);

            // Initialize Picture Edit Module
            InitializePictureEditComponents();

            // Initialize Picture Saving Module
            InitializePictureSavingModule();

			listBoxProfilesAvailable.SelectedIndex = 0;
		}

		const string FORM_TITLE_PREFIX = "QQ Album Show Creator";

		#region Control Profile Initialization and Applying
		Hashtable _profiles;

		/// <summary>
		/// Get the key of a profile for the profile hash table.
		/// </summary>
		/// <param name="profile">The XML document segment representing that profile</param>
		/// <returns>A string of key representing that profile only, null if profile does not have enough information.</returns>
		protected string GenerateProfileKey(XElement profile) {
			try {
				string key = profile.Attribute("name").Value + " " + profile.Attribute("type").Value;
				return key;
			} catch {
				return null;
			}
		}

		/// <summary>
		/// Load profiles from an XML file into a hashtable in memory.
		/// </summary>
		/// <returns>true if successfully read the profiles, false if any error occurs.</returns>
		protected bool LoadProfiles() {
			XDocument doc = XDocument.Parse(global::QQSideShowCreator.Properties.Resources.QQSideShowConf);
			XElement profilesXML = doc.Element("QQAlbumSideShow").Element("UIProfiles");

			// For each profile in the configuration file
			foreach ( XElement profileXML in profilesXML.Elements("Profile") ) {
				// prepare a profile object
				ControlsProfile profileObj = new ControlsProfile();

				try {
					profileObj.ImageName = profileXML.Attribute("img").Value;
				} catch {
					profileObj.ImageName = "";
				}

				// read form setting in the profile document
				ControlSetting formSetting = new ControlSetting(this);
				formSetting.ControlSize = new Size(
					int.Parse(profileXML.Element("ContainerForm").Attribute("width").Value),
					int.Parse(profileXML.Element("ContainerForm").Attribute("height").Value));
				profileObj.Add(formSetting);

				// read each of other control settings in the profile document
				foreach ( XElement controlXML in profileXML.Elements("Control") ) {
					int multiplier = 1;
					try {
						multiplier = int.Parse(controlXML.Attribute("sizemultiplier").Value);
					} catch {
						multiplier = 1;	// default value
					}

					string controlName = controlXML.Attribute("name").Value;
					Control control = this.Controls[controlName];
					ControlSetting controlSetting = new ControlSetting(this.Controls[controlXML.Attribute("name").Value]);
					controlSetting.ControlSize = new Size(
						int.Parse(controlXML.Attribute("width").Value) * multiplier,
						int.Parse(controlXML.Attribute("height").Value) * multiplier);
					controlSetting.TopLeft = new Point(
						int.Parse(controlXML.Attribute("x").Value),
						int.Parse(controlXML.Attribute("y").Value));
					controlSetting.Dock = DockStyle.None;

					profileObj.Add(controlSetting);
				}

				// Set other decimal settings of the image fragments in this profile
				try {
					profileObj.ColumnCount = int.Parse(profileXML.Element("FragmentSetting").Attribute("xcount").Value);
					profileObj.RowCount = int.Parse(profileXML.Element("FragmentSetting").Attribute("ycount").Value);
					profileObj.FragmentSize = new Size(
						int.Parse(profileXML.Element("FragmentSetting").Attribute("width").Value),
						int.Parse(profileXML.Element("FragmentSetting").Attribute("height").Value));
					profileObj.HorizontalPadding = int.Parse(profileXML.Element("FragmentSetting").Attribute("xpadding").Value);
					profileObj.VerticalPadding = int.Parse(profileXML.Element("FragmentSetting").Attribute("ypadding").Value);
				} catch {
					return false;
				}

				_profiles.Add(this.GenerateProfileKey(profileXML), profileObj);				
			}

			return true;
		}

		/// <summary>
		/// Applying a profile by the key uniquely identifies that profile
		/// </summary>
		/// <param name="key">The key uniquely identifies the profile </param>
		/// <returns>true if the profile is applied successfully, otherwise false is returned.</returns>
		protected bool ApplyProfile(string key) {
			try {
				ControlsProfile profile = (ControlsProfile)_profiles[ key ];
				foreach ( ControlSetting setting in profile ) {
					if (setting.ControlSize != Size.Empty)
						setting.Control.Size = setting.ControlSize;
					if ( setting.TopLeft != Point.Empty )
						setting.Control.Location = setting.TopLeft;
					if ( setting.Dock != DockStyle.None )
						setting.Control.Dock = setting.Dock;
				}

				Bitmap frame_new = (Bitmap)global::QQSideShowCreator.Properties.Resources.ResourceManager.GetObject(profile.ImageName);
				RenewProfileForEditing(ref frame_new);
				RenewProfileForSaving(profile.FragmentSize.Width, profile.FragmentSize.Height, profile.HorizontalPadding,
					profile.VerticalPadding, profile.RowCount, profile.ColumnCount);
				
				return true;
			} catch {
				return false;
			}
		}
		#endregion

		#region UI Control Events Responding Function
		private void exitToolStripMenuItem_Click( object sender, EventArgs e ) {
            CleanUp();
            Application.Exit();
        }

        private void buttonBrowse_Click( object sender, EventArgs e ) {
            FolderBrowserDialog dlg = new FolderBrowserDialog();
            dlg.Description = "Please select the folder to place generated images.";
            dlg.ShowNewFolderButton = true;
            dlg.RootFolder = Environment.SpecialFolder.Desktop;
            dlg.SelectedPath = textOutputFolder.Text;
            DialogResult dr = dlg.ShowDialog();
            if ( dr == DialogResult.OK ) {
                textOutputFolder.Text = dlg.SelectedPath;
            }
            dlg.Dispose();
        }

        private void openToolStripMenuItem_Click( object sender, EventArgs e ) {
            OpenFileDialog dlg = new OpenFileDialog();
            dlg.Multiselect = false;
            dlg.InitialDirectory = Environment.GetFolderPath( Environment.SpecialFolder.MyPictures );
            dlg.Filter = "All Supported Image Files(*.BMP;*.JPG;*.GIF;*.PNG;*.TIFF;*.EXIF)|*.BMP;*.JPG;*.GIF;*.PNG;*.TIFF;*.EXIF";
            
            DialogResult dr = dlg.ShowDialog();
            if ( dr == DialogResult.OK ) {
                OpenImageFile( dlg.FileName );
            }
            this.sFileSimpleName = dlg.SafeFileName;
            dlg.Dispose();
        }

        private void toolOpenFiles_Click( object sender, EventArgs e ) {
            openToolStripMenuItem_Click( sender, e );
        }

        private void buttonOriginal_Click( object sender, EventArgs e ) {
            if ( imgSource == null )
                return;

            if ( MIN_SCALE > 1.0f )
                ZoomingScale = MIN_SCALE;
            else
                ZoomingScale = 1.0f;
        }

        private void buttonFitImage_Click( object sender, EventArgs e ) {
            if ( imgSource == null )
                return;

            // the "best fit" means the minimal scale, that is, no blank is left unrendered
            ZoomingScale = trackBar1.Minimum * 1.0f / SCALE_TO_INT;
        }

        private void checkPreviewOn_CheckedChanged( object sender, EventArgs e ) {
            if ( imgSource == null )
                return;

            RenderPictureBox();
        }

        private void trackBar1_Scroll( object sender, EventArgs e ) {
            if ( imgSource == null )
                return;

            ZoomingScale = trackBar1.Value * 1.0f / SCALE_TO_INT;            
        }

        private void pictureBox1_MouseDown( object sender, MouseEventArgs e ) {
            if ( imgSource == null )
                return;

            if ( e.Button == MouseButtons.Left && imgSource != null ) {
                bDragLock = true;
                pointMouseDown = e.Location;
                pointOldViewportTopLeft = pointViewportTopLeft;
            }
        }

        private void pictureBox1_MouseMove( object sender, MouseEventArgs e ) {
            if ( bDragLock == true ) {
                float nDeltaX = e.X - pointMouseDown.X;
                float nDeltaY = e.Y - pointMouseDown.Y;
                nDeltaX /= ZoomingScale;
                nDeltaY /= ZoomingScale;
                ViewPortTopLeft = new Point(
                    Convert.ToInt32( pointOldViewportTopLeft.X - nDeltaX ),
                    Convert.ToInt32( pointOldViewportTopLeft.Y - nDeltaY ) );
                //this.Text = "Left Point @ " + e.Location.ToString();
                GC.Collect();
            }
        }

        private void pictureBox1_MouseUp( object sender, MouseEventArgs e ) {
            if ( imgSource == null )
                return;

            if ( bDragLock )
                bDragLock = false;
        }

        private void pictureBox1_MouseLeave( object sender, EventArgs e ) {
            if ( imgSource == null )
                return;

            if ( bDragLock )
                bDragLock = false;
        }

        private void buttonOptions_Click( object sender, EventArgs e ) {
            if ( imgSource == null )
                return;

            SettingsForm form = new SettingsForm( sizeFileResolution, formatOutputFile, this );
            form.ShowDialog();
        }

        private void buttonConvert_Click( object sender, EventArgs e ) {
            if ( imgSource == null )
                return;
            SavePictures();
            MessageBox.Show( "Conversion Completed!", "Congratulations" );
        }

        private void aboutToolStripMenuItem_Click( object sender, EventArgs e ) {
            AboutBox about = new AboutBox();
            about.ShowDialog();
        }

        private void toolFlipHorizontal_Click( object sender, EventArgs e ) {
            if ( imgSource == null )
                return;

            imgSource.RotateFlip( RotateFlipType.RotateNoneFlipX );
            RenderPictureBox();
        }

        private void toolFlipVertical_Click( object sender, EventArgs e ) {
            if ( imgSource == null )
                return;
            imgSource.RotateFlip( RotateFlipType.RotateNoneFlipY );
            RenderPictureBox();
		}
		
		private void listBoxProfilesAvailable_SelectedIndexChanged(object sender, EventArgs e) {
			ApplyProfile((string)listBoxProfilesAvailable.SelectedItem);
			if ( imgSource != null ) {
				RenderPictureBox();
			}
		}
		#endregion

		

	}
}
